package com.homedo.microservice.open.service.gateway.manager.web.gateway.service;

import com.google.common.collect.Lists;
import com.homedo.common.bean.data.enums.ResponseEnum;
import com.homedo.common.bean.vo.Pagination;
import com.homedo.common.bean.vo.context.UserContext;
import com.homedo.common.dao.bean.po.base.BasePo;
import com.homedo.common.dao.bean.po.enhanced.base.BaseEnhanced;
import com.homedo.common.exception.HomedoException;
import com.homedo.common.service.BaseService;
import com.homedo.common.util.Detect;
import com.homedo.microservice.open.service.gateway.manager.web.gateway.bean.enums.forroute.StatusEnum4Route;
import com.homedo.microservice.open.service.gateway.manager.web.gateway.bean.enums.forrouteservice.StatusEnum4RouteService;
import com.homedo.microservice.open.service.gateway.manager.web.gateway.bean.po.RouteVersion;
import com.homedo.microservice.open.service.gateway.manager.web.gateway.bean.po.enhanced.RouteEnhanced;
import com.homedo.microservice.open.service.gateway.manager.web.gateway.bean.po.enhanced.RouteServiceEnhanced;
import com.homedo.microservice.open.service.gateway.manager.web.gateway.bean.po.enhanced.RouteVersionEnhanced;
import com.homedo.microservice.open.service.gateway.manager.web.gateway.bean.query.RouteVersionQuery;
import com.homedo.microservice.open.service.gateway.manager.web.gateway.persistence.dao.RouteVersionDao;
import com.homedo.microservice.open.service.gateway.manager.web.gateway.support.ApplicationNameHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author 作者 jgshun
 * @date 创建时间 2018年09月19日 13时40分00秒
 */
@Service
public class RouteVersionService extends BaseService<RouteVersion> {
    @Autowired
    private RouteVersionDao routeVersionDao;
    @Autowired
    private RouteService routeService;
    @Autowired
    private RouteServiceService routeServiceService;

    @Override
    public List<RouteVersionEnhanced> getEnhanceds(List<?> ids, UserContext userContext) {
        List<RouteVersion> routeVersions = routeVersionDao.getListByIds(ids, RouteVersion.class);

        if (!Detect.notEmpty(routeVersions)) {
            return null;
        }

        List<RouteVersionEnhanced> routeVersionEnhanceds = this.convent2Enhanceds(routeVersions);

        this.appendEnhancedCommons(routeVersionEnhanceds, userContext);

        return routeVersionEnhanceds;
    }


    @Override
    public List<RouteVersionEnhanced> getEnhanceds4Active(List<?> ids, UserContext userContext) {
        List<RouteVersion> routeVersions = routeVersionDao.getListByIdsGreaterThanMark0(ids, RouteVersion.class);

        if (!Detect.notEmpty(routeVersions)) {
            return null;
        }

        List<RouteVersionEnhanced> routeVersionEnhanceds = this.convent2Enhanceds(routeVersions);

        this.appendEnhancedCommons(routeVersionEnhanceds, userContext);

        return routeVersionEnhanceds;
    }


    @Override
    public List<RouteVersionEnhanced> convent2Enhanceds(List<? extends BasePo> pos) {
        List<RouteVersion> routeVersions = (List<RouteVersion>) pos;
        List<RouteVersionEnhanced> routeVersionEnhanceds = Lists.newArrayList();
        routeVersions.forEach(e -> routeVersionEnhanceds.add(new RouteVersionEnhanced(e)));
        return routeVersionEnhanceds;
    }

    public Pagination<RouteVersionEnhanced> getPagination(RouteVersionQuery routeVersionQuery, Pagination<RouteVersionEnhanced> pagination, UserContext userContext) {
        Pagination<RouteVersion> routeVersionPagination = routeVersionDao.getPagination(routeVersionQuery, pagination.copy());
        pagination.setCount(routeVersionPagination.getCount());
        if (!Detect.notEmpty(routeVersionPagination.getItems())) {
            return pagination;
        }

        pagination.setItems(this.convent2Enhanceds(routeVersionPagination.getItems()));

        this.appendEnhancedCommons(pagination.getItems(), userContext);

        return pagination;
    }

    public List<RouteVersionEnhanced> getEnhanceds4Route(List<String> routeIds, UserContext userContext) {
        List<RouteVersion> routeVersions = routeVersionDao.getListByRouteIds(routeIds);

        if (!Detect.notEmpty(routeVersions)) {
            return null;
        }

        List<RouteVersionEnhanced> routeVersionEnhanceds = this.convent2Enhanceds(routeVersions);

        this.appendEnhancedCommons(routeVersionEnhanceds, userContext);

        return routeVersionEnhanceds;
    }

    public List<RouteVersionEnhanced> getEnhanceds4Application(String applicationName, List<StatusEnum4Route> statusEnum4Routes, UserContext userContext) {
        List<RouteEnhanced> routeEnhanceds = routeService.getEnhanceds4Application(applicationName, statusEnum4Routes, userContext);
        if (!Detect.notEmpty(routeEnhanceds)) {
            return null;
        }
        List<RouteVersionEnhanced> routeVersionEnhanceds = Lists.newArrayList();
        routeEnhanceds.forEach(e -> {
            if (Detect.notEmpty(e.getRouteVersionEnhanceds())) {
                routeVersionEnhanceds.addAll(e.getRouteVersionEnhanceds());
            }
        });

        this.appendEnhancedCommons(routeVersionEnhanceds, userContext);

        return routeVersionEnhanceds;
    }

    @Override
    public List<RouteVersionEnhanced> appendEnhancedCommons(List<? extends BaseEnhanced> enhancedItems, UserContext userContext) {
        List<RouteVersionEnhanced> routeVersionEnhanceds = (List<RouteVersionEnhanced>) enhancedItems;

        this.appendRouteServiceEnhanced(routeVersionEnhanceds, userContext);
        //不要添加填充路由详情数据，会造成路由填充版本时的循环调用  严重===一定放在方法外部填充路由详情

        return routeVersionEnhanceds;
    }

    public List<RouteVersionEnhanced> appendRouteServiceEnhanced(List<RouteVersionEnhanced> routeVersionEnhanceds, UserContext userContext) {
        List<String> routeServiceIds = routeVersionEnhanceds.stream()
                .map(RouteVersionEnhanced::getRouteServiceEnhanced).filter(e -> e != null && Detect.notEmpty(e.getId())).collect(Collectors.toList())
                .stream().map(RouteServiceEnhanced::getId).collect(Collectors.toList());
        if (!Detect.notEmpty(routeServiceIds)) {
            return routeVersionEnhanceds;
        }

        List<RouteServiceEnhanced> routeServiceEnhanceds = routeServiceService.getEnhanceds(routeServiceIds, userContext);

        if (!Detect.notEmpty(routeServiceEnhanceds)) {
            return routeVersionEnhanceds;
        }

        this.appendRouteServiceEnhanced(routeVersionEnhanceds, routeServiceEnhanceds, userContext);

        return routeVersionEnhanceds;
    }


    public RouteVersion addRouteVersion(RouteVersion routeVersion, UserContext userContext) {
        this.checkAdd(routeVersion);

        routeVersion.setCreateTime(new Date());
        routeVersion.setUpdateTime(new Date());

        routeVersion = routeVersionDao.saveSelective(routeVersion);

        return routeVersion;
    }

    public void updateRouteVersion(Integer id, String version, String serviceId, String comment, Integer status, UserContext userContext) {
        RouteVersion routeVersion = routeVersionDao.getById(id);

        this.checkUpdate(routeVersion, version, serviceId);

        if (Detect.notEmpty(version)) {
            routeVersion.setVersion(version);
        }
        if (Detect.notEmpty(serviceId)) {
            routeVersion.setServiceId(serviceId);
        }
        if (Detect.notEmpty(comment)) {
            routeVersion.setComment(comment);
        }
        if (status != null && StatusEnum4Route.getStatusEnumByCode(status.shortValue()) != null) {
            routeVersion.setStatus(status);
        }
        routeVersion.setUpdateTime(new Date());

        routeVersionDao.updateByPrimaryKeySelective(routeVersion);
    }

    private void checkUpdate(RouteVersion dbRouteVersion, String version, String serviceId) {
        if (Detect.notEmpty(version)) {
            if (!this.checkVersion(version)) {
                throw new HomedoException("[只能是英文加数字，以“.”分隔;以英文或数字开头]");
            }
            RouteVersion record = new RouteVersion();
            record.setRouteId(dbRouteVersion.getRouteId());
            record.setVersion(version);

            record = routeVersionDao.getOneByRecord(record);
            if (record != null && !record.getId().equals(dbRouteVersion.getId())) {
                throw new HomedoException("[同一个路由下不能出现相同的版本号]");
            }
        }

        if (Detect.notEmpty(serviceId) && !serviceId.equals(dbRouteVersion.getServiceId())) {
            RouteServiceEnhanced routeServiceEnhanced = routeServiceService.getEnhanced(serviceId, null);
            if (routeServiceEnhanced.getStatus() != StatusEnum4RouteService.EFFECTIVE) {
                throw new HomedoException("[服务组不可用]");
            }
            if (!ApplicationNameHolder.get().equals(routeServiceEnhanced.getApplicationName())) {
                throw new HomedoException(ResponseEnum.PERMISSION_DENIED);
            }
        }
    }

    private void checkAdd(RouteVersion routeVersion) {
        if (!Detect.notEmpty(routeVersion.getRouteId()) || !Detect.notEmpty(routeVersion.getVersion())
                || !Detect.notEmpty(routeVersion.getServiceId()) || !Detect.notEmpty(routeVersion.getComment())
                || routeVersion.getStatus() == null) {
            throw new HomedoException(ResponseEnum.PARAM_ERROR);
        }

        if (!this.checkVersion(routeVersion.getVersion())) {
            throw new HomedoException("[只能是英文加数字，以“.”分隔;以英文或数字开头]");
        }

        RouteServiceEnhanced routeServiceEnhanced = routeServiceService.getEnhanced(routeVersion.getServiceId(), null);
        if (routeServiceEnhanced.getStatus() != StatusEnum4RouteService.EFFECTIVE) {
            throw new HomedoException("[服务组不可用]");
        }
        if (!ApplicationNameHolder.get().equals(routeServiceEnhanced.getApplicationName())) {
            throw new HomedoException(ResponseEnum.PERMISSION_DENIED);
        }

        RouteVersion record = new RouteVersion();
        record.setRouteId(routeVersion.getRouteId());
        record.setVersion(routeVersion.getVersion());

        record = routeVersionDao.getOneByRecord(record);
        if (record != null) {
            throw new HomedoException("[同一个路由下不能出现相同的版本号]");
        }
    }

    private boolean checkVersion(String version) {
        Pattern pattern = Pattern.compile("^[A-Za-z0-9][A-Za-z0-9\\.]+$");//只能是英文加数字加.
        Matcher m = pattern.matcher(version);
        return m.matches();
    }

    private void appendRouteServiceEnhanced(List<RouteVersionEnhanced> routeVersionEnhanceds, List<RouteServiceEnhanced> routeServiceEnhanceds, UserContext userContext) {
        routeVersionEnhanceds.forEach(e -> {
            this.appendRouteServiceEnhanced(e, routeServiceEnhanceds, userContext);
        });
    }

    private void appendRouteServiceEnhanced(RouteVersionEnhanced routeVersionEnhanced, List<RouteServiceEnhanced> routeServiceEnhanceds, UserContext userContext) {
        routeServiceEnhanceds.forEach(e -> {
            if (routeVersionEnhanced.getRouteServiceEnhanced() != null && e.getId().equals(routeVersionEnhanced.getRouteServiceEnhanced().getId())) {
                routeVersionEnhanced.setRouteServiceEnhanced(e);
                return;
            }
        });
    }

}
